{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pass2Path Network - Train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import os\n",
    "import pickle\n",
    "import copy\n",
    "import string\n",
    "import json\n",
    "import csv\n",
    "import time\n",
    "import math\n",
    "from word2keypress import Keyboard\n",
    "from ast import literal_eval\n",
    "from tensorflow.contrib.seq2seq.python.ops import beam_search_ops\n",
    "from pathlib import Path\n",
    "from edit_distance_backtrace import find_med_backtrace\n",
    "import random\n",
    "from collections import OrderedDict\n",
    "from pass2path_model import Pass2PathModel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "Preprocessing:\n",
    "We need to create look-up tables in order to translate characters to mathematical representation.\n",
    "'''\n",
    "\n",
    "# CODES = {'<PAD>': 0, '<EOS>': 1, '<UNK>': 2, '<GO>': 3 }\n",
    "CODES = {'<GO>': 0, '<EOS>': 1, '<UNK>': 2}\n",
    "# chars = list(string.ascii_letters) + list(string.punctuation) +\n",
    "# list(string.digits) + [\" \", \"\\t\", \"\\x03\", \"\\x04\"]\n",
    "def create_lookup_tables_from_lst(char_lst):\n",
    "    '''\n",
    "    This function creates a dictionary out of a list with the added codes representing padding,\n",
    "    unknows components, start and end of a sequence\n",
    "    '''\n",
    "    # <EOS> acts as <PAD>\n",
    "    # CODES = {'<PAD>': 0, '<EOS>': 1, '<UNK>': 2, '<GO>': 3 }\n",
    "    # chars = list(string.ascii_letters) + list(string.punctuation) +\n",
    "    # list(string.digits) + [\" \", \"\\t\", \"\\x03\", \"\\x04\"]\n",
    "\n",
    "    # make a list of unique chars (from https://stackoverflow.com/a/480227)\n",
    "    seen = set()\n",
    "    seen_add = seen.add\n",
    "    vocab = [x for x in char_lst if not (x in seen or seen_add(x))]\n",
    "\n",
    "    if len(vocab) < 100:\n",
    "        print(vocab)\n",
    "        print(char_lst)\n",
    "    # (1)\n",
    "    # starts with the special tokens\n",
    "    vocab_to_int = copy.copy(CODES)\n",
    "\n",
    "    # the index (v_i) will starts from 4 (the 2nd arg in enumerate() specifies\n",
    "    # the starting index)\n",
    "    # since vocab_to_int already contains special tokens\n",
    "    for v_i, v in enumerate(vocab, len(CODES)):\n",
    "        vocab_to_int[str(v)] = v_i # opposite would be int()\n",
    "    int_to_vocab = {v_i: v for v, v_i in vocab_to_int.items()}\n",
    "\n",
    "    return vocab_to_int, int_to_vocab\n",
    "\n",
    "def build_path_vocab(origin_vocab):\n",
    "    '''\n",
    "    This functions combines the path dictionary with the added codes.\n",
    "    '''\n",
    "    int_lst = sorted(list(origin_vocab.values()))\n",
    "    path_to_int_vocab, int_to_path_vocab = create_lookup_tables_from_lst(int_lst)\n",
    "    return path_to_int_vocab, int_to_path_vocab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Globals\n",
    "kb = Keyboard()\n",
    "# thisfolder = Path(__file__).absolute().parent\n",
    "# TRANS_to_IDX = json.load((thisfolder / 'data/trans_dict_2idx.json').open()) #\n",
    "# py\n",
    "with open(('./data/trans_dict_2idx.json')) as f:\n",
    "    TRANS_to_IDX = json.load(f) # jupyter\n",
    "IDX_to_TRANS = {v: literal_eval(k) for k, v in TRANS_to_IDX.items()}\n",
    "char_lst = list(string.ascii_letters) + list(string.digits) + list(string.punctuation) + [\" \", \"\\t\", \"\\x03\", \"\\x04\"]\n",
    "source_vocab_to_int, source_int_to_vocab = create_lookup_tables_from_lst(char_lst)\n",
    "target_vocab_to_int, target_int_to_vocab = build_path_vocab(TRANS_to_IDX)\n",
    "NUM_SAMPLES_LARGE_DS = 117574260\n",
    "NUM_SAMPLES_CORNELL_DS = 11667608\n",
    "tf.app.flags.FLAGS.__flags.clear()\n",
    "\n",
    "# Network parameters\n",
    "tf.app.flags.DEFINE_string('cell_type', 'lstm', 'RNN cell for encoder and decoder, default: lstm')\n",
    "# tf.app.flags.DEFINE_string('attention_type', 'bahdanau', 'Attention mechanism: (bahdanau, luong), default: bahdanau')\n",
    "tf.app.flags.DEFINE_integer('hidden_units', 128, 'Number of hidden units in each layer')\n",
    "tf.app.flags.DEFINE_integer('depth', 3 , 'Number of layers in each encoder and decoder')\n",
    "tf.app.flags.DEFINE_integer('embedding_size', 200, 'Embedding dimensions of encoder and decoder inputs')\n",
    "tf.app.flags.DEFINE_integer('num_encoder_symbols', len(source_int_to_vocab), 'Source vocabulary size')\n",
    "tf.app.flags.DEFINE_integer('num_decoder_symbols', len(target_int_to_vocab), 'Target vocabulary size')\n",
    "tf.app.flags.DEFINE_string('ds_csv_path', 'cleaned_pw_paths_tr_10000.csv', 'path to the csv file containing the dataset')\n",
    "tf.app.flags.DEFINE_boolean('use_residual', True, 'Use residual connection between layers')\n",
    "# tf.app.flags.DEFINE_boolean('attn_input_feeding', False, 'Use input feeding method in attentional decoder')\n",
    "tf.app.flags.DEFINE_boolean('use_dropout', True, 'Use dropout in each rnn cell')\n",
    "tf.app.flags.DEFINE_float('dropout_rate', 0.4, 'Dropout probability for input/output/state units (0.0: no dropout)')\n",
    "tf.app.flags.DEFINE_integer('edit_distance', 3, 'Filter out samples with edit distance greater than this number')\n",
    "# Training parameters\n",
    "tf.app.flags.DEFINE_float('learning_rate', 0.001, 'Learning rate')\n",
    "tf.app.flags.DEFINE_float('max_gradient_norm', 1.0, 'Clip gradients to this norm')\n",
    "tf.app.flags.DEFINE_integer('batch_size', 50, 'Batch size')\n",
    "tf.app.flags.DEFINE_integer('max_epochs', 500, 'Maximum # of training epochs')\n",
    "# tf.app.flags.DEFINE_integer('max_load_batches', 20, 'Maximum # of batches to load at one time')\n",
    "tf.app.flags.DEFINE_integer('max_seq_length', 62, 'Maximum sequence length')\n",
    "tf.app.flags.DEFINE_integer('display_freq', 10, 'Display training status every this iteration')\n",
    "tf.app.flags.DEFINE_integer('save_freq', 11500, 'Save model checkpoint every this iteration')\n",
    "tf.app.flags.DEFINE_integer('valid_freq', 40, 'Evaluate model every this iteration: valid_data needed')\n",
    "tf.app.flags.DEFINE_string('optimizer', 'adam', 'Optimizer for training: (adadelta, adam, rmsprop)')\n",
    "tf.app.flags.DEFINE_string('model_dir', 'model/', 'Path to save model checkpoints')\n",
    "tf.app.flags.DEFINE_string('summary_dir', 'model/summary', 'Path to save model summary')\n",
    "tf.app.flags.DEFINE_string('model_name', 'pass2path.ckpt', 'File name used for model checkpoints')\n",
    "# tf.app.flags.DEFINE_boolean('shuffle_each_epoch', True, 'Shuffle training dataset for each epoch')\n",
    "# tf.app.flags.DEFINE_boolean('sort_by_length', True, 'Sort pre-fetched minibatches by their target sequence lengths')\n",
    "tf.app.flags.DEFINE_boolean('use_fp16', False, 'Use half precision float16 instead of float32 as dtype')\n",
    "\n",
    "# Runtime parameters\n",
    "tf.app.flags.DEFINE_boolean('allow_soft_placement', True, 'Allow device soft placement')\n",
    "tf.app.flags.DEFINE_boolean('log_device_placement', False, 'Log placement of ops on devices')\n",
    "\n",
    "FLAGS = tf.app.flags.FLAGS"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def set_train_flags(cell_type='lstm', hidden_units=128, num_layers=3, embed_size=200, path_to_ds='cleaned_pw_paths_tr.csv',\n",
    "                   use_residual=False, keep_prob=0.6, edit_distance=2, lr=0.001, batch_size=50, epochs=10,\n",
    "                   display_step=100, save_freq=11500):\n",
    "    \n",
    "    tf.app.flags.FLAGS.__flags.clear()\n",
    "\n",
    "    # Network parameters\n",
    "    tf.app.flags.DEFINE_string('cell_type', cell_type , 'RNN cell for encoder and decoder, default: lstm')\n",
    "    tf.app.flags.DEFINE_integer('hidden_units', hidden_units, 'Number of hidden units in each layer')\n",
    "    tf.app.flags.DEFINE_integer('depth', num_layers , 'Number of layers in each encoder and decoder')\n",
    "    tf.app.flags.DEFINE_integer('embedding_size', embed_size, 'Embedding dimensions of encoder and decoder inputs')\n",
    "    tf.app.flags.DEFINE_integer('num_encoder_symbols', len(source_int_to_vocab), 'Source vocabulary size')\n",
    "    tf.app.flags.DEFINE_integer('num_decoder_symbols', len(target_int_to_vocab), 'Target vocabulary size')\n",
    "    tf.app.flags.DEFINE_string('ds_csv_path', path_to_ds, 'path to the csv file containing the dataset')\n",
    "    tf.app.flags.DEFINE_boolean('use_residual', use_residual, 'Use residual connection between layers')\n",
    "    tf.app.flags.DEFINE_boolean('use_dropout', True, 'Use dropout in each rnn cell')\n",
    "    tf.app.flags.DEFINE_float('dropout_rate', 1 - keep_prob, 'Dropout probability for input/output/state units (0.0: no dropout)')\n",
    "    tf.app.flags.DEFINE_integer('edit_distance', edit_distance, 'Filter out samples with edit distance greater than this number')\n",
    "    # Training parameters\n",
    "    tf.app.flags.DEFINE_float('learning_rate', lr, 'Learning rate')\n",
    "    tf.app.flags.DEFINE_float('max_gradient_norm', 1.0, 'Clip gradients to this norm')\n",
    "    tf.app.flags.DEFINE_integer('batch_size', batch_size, 'Batch size')\n",
    "    tf.app.flags.DEFINE_integer('max_epochs', epochs, 'Maximum # of training epochs')\n",
    "    # tf.app.flags.DEFINE_integer('max_load_batches', 20, 'Maximum # of batches\n",
    "    # to load at one time')\n",
    "    tf.app.flags.DEFINE_integer('max_seq_length', 62, 'Maximum sequence length')\n",
    "    tf.app.flags.DEFINE_integer('display_freq', display_step, 'Display training status every this iteration')\n",
    "    tf.app.flags.DEFINE_integer('save_freq', save_freq, 'Save model checkpoint every this iteration')\n",
    "    tf.app.flags.DEFINE_integer('valid_freq', 3 * display_step, 'Evaluate model every this iteration: valid_data needed')\n",
    "    tf.app.flags.DEFINE_string('optimizer', 'adam', 'Optimizer for training: (adadelta, adam, rmsprop)')\n",
    "    tf.app.flags.DEFINE_string('model_dir', './model/', 'Path to save model checkpoints')\n",
    "    tf.app.flags.DEFINE_string('summary_dir', './model/summary', 'Path to save model summary')\n",
    "    tf.app.flags.DEFINE_string('model_name', 'pass2path.ckpt', 'File name used for model checkpoints')\n",
    "    # Ignore Cmmand Line\n",
    "    tf.app.flags.DEFINE_string('t', '', '')\n",
    "    tf.app.flags.DEFINE_string('d', '', '')\n",
    "    tf.app.flags.DEFINE_string('b', '', '')\n",
    "    tf.app.flags.DEFINE_string('q', '', '')\n",
    "    tf.app.flags.DEFINE_string('c', '', '')\n",
    "    tf.app.flags.DEFINE_string('s', '', '')\n",
    "    tf.app.flags.DEFINE_string('e', '', '')\n",
    "    tf.app.flags.DEFINE_string('z', '', '')\n",
    "    tf.app.flags.DEFINE_string('l', '', '')\n",
    "    tf.app.flags.DEFINE_string('m', '', '')\n",
    "    tf.app.flags.DEFINE_string('w', '', '')\n",
    "    tf.app.flags.DEFINE_string('i', '', '')\n",
    "    tf.app.flags.DEFINE_string('f', '', '')\n",
    "    tf.app.flags.DEFINE_string('r', '', '')\n",
    "    tf.app.flags.DEFINE_string('k', '', '')\n",
    "    # tf.app.flags.DEFINE_boolean('shuffle_each_epoch', True, 'Shuffle training\n",
    "    # dataset for each epoch')\n",
    "    # tf.app.flags.DEFINE_boolean('sort_by_length', True, 'Sort pre-fetched\n",
    "    # minibatches by their target sequence lengths')\n",
    "    tf.app.flags.DEFINE_boolean('use_fp16', False, 'Use half precision float16 instead of float32 as dtype')\n",
    "\n",
    "    # Runtime parameters\n",
    "    tf.app.flags.DEFINE_boolean('allow_soft_placement', True, 'Allow device soft placement')\n",
    "    tf.app.flags.DEFINE_boolean('log_device_placement', False, 'Log placement of ops on devices')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Globals\n",
    "kb = Keyboard()\n",
    "# thisfolder = Path(__file__).absolute().parent\n",
    "# TRANS_to_IDX = json.load((thisfolder / 'data/trans_dict_2idx.json').open()) # py\n",
    "with open(('./data/trans_dict_2idx.json')) as f:\n",
    "    TRANS_to_IDX = json.load(f) # jupyter\n",
    "IDX_to_TRANS = {v: literal_eval(k) for k, v in TRANS_to_IDX.items()}\n",
    "char_lst = list(string.ascii_letters) + list(string.digits) + list(string.punctuation) + [\" \", \"\\t\", \"\\x03\", \"\\x04\"]\n",
    "source_vocab_to_int, source_int_to_vocab = create_lookup_tables_from_lst(char_lst)\n",
    "target_vocab_to_int, target_int_to_vocab = build_path_vocab(TRANS_to_IDX)\n",
    "NUM_SAMPLES_LARGE_DS = 117574260\n",
    "set_train_flags(path_to_ds='cleaned_pw_paths_tr_10000.csv')\n",
    "FLAGS = tf.app.flags.FLAGS"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_model(session, FLAGS):\n",
    "\n",
    "    config = OrderedDict(sorted((dict([(key,val.value) for key,val in FLAGS.__flags.items()])).items()))\n",
    "    model = Pass2PathModel(config, 'train')\n",
    "\n",
    "    ckpt = tf.train.get_checkpoint_state(FLAGS.model_dir)\n",
    "    if (ckpt):\n",
    "        print(\"Found a checkpoint state...\")\n",
    "        print(ckpt.model_checkpoint_path)\n",
    "    if (ckpt and tf.train.checkpoint_exists(ckpt.model_checkpoint_path)):\n",
    "        print('Reloading model parameters..')\n",
    "        model.restore(session, ckpt.model_checkpoint_path)\n",
    "        \n",
    "    else:\n",
    "        if not os.path.exists(FLAGS.model_dir):\n",
    "            os.makedirs(FLAGS.model_dir)\n",
    "        print('Created new model parameters..')\n",
    "        session.run(tf.global_variables_initializer())\n",
    "   \n",
    "    return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def input_to_ids(source_pws_lst, target_paths_lst, source_vocab_to_int, target_vocab_to_int):\n",
    "    \"\"\"\n",
    "    1st, 2nd args: lists passwords and paths to be converted\n",
    "    3rd, 4th args: lookup tables for 1st and 2nd args respectively   \n",
    "    return: A tuple of lists (source_id_pass, target_id_path) converted\n",
    "    Will use for mini-batches of (passwords, paths)\n",
    "    \"\"\"\n",
    "    # empty list of converted passwords and paths\n",
    "    source_pass_id = []\n",
    "    target_path_id = []\n",
    "    \n",
    "    max_source_pass_length = max([len(password) for password in source_pws_lst])\n",
    "    max_target_path_length = max([len(path) for path in target_paths_lst])\n",
    "    \n",
    "    # iterating through each password (# of passwords & paths is the same)\n",
    "    for i in range(len(source_pws_lst)):\n",
    "        # extract password, one by one\n",
    "        source_password = source_pws_lst[i]\n",
    "#         print(target_paths_lst)\n",
    "        target_path = target_paths_lst[i]\n",
    "        \n",
    "        # make a list of tokens/words (extraction) from the chosen password\n",
    "        source_tokens = list(source_password)\n",
    "        target_tokens = [str(t) for t in target_path]\n",
    "        \n",
    "        # empty list of converted words to index in the chosen password\n",
    "        source_token_id = []\n",
    "        target_token_id = []\n",
    "        \n",
    "        for index, token in enumerate(source_tokens):\n",
    "            if (token != \"\"):\n",
    "                if (source_vocab_to_int.get(token)):\n",
    "                    source_token_id.append(source_vocab_to_int[token])\n",
    "        \n",
    "        for index, token in enumerate(target_tokens):\n",
    "            if (token != \"\"):\n",
    "                if (target_vocab_to_int.get(token)):\n",
    "                    target_token_id.append(target_vocab_to_int[token])\n",
    "                \n",
    "        # put <EOS> token at the end of the chosen target sentence\n",
    "        # this token suggests when to stop creating a sequence\n",
    "        target_token_id.append(target_vocab_to_int['<EOS>'])\n",
    "            \n",
    "        # add each converted sentences in the final list\n",
    "        source_pass_id.append(source_token_id)\n",
    "        target_path_id.append(target_token_id)\n",
    "    \n",
    "    return source_pass_id, target_path_id\n",
    "\n",
    "def _parse_line(line):\n",
    "    '''\n",
    "    This helper function parses a line from the CSV dataset to a dictionary and a target.\n",
    "    '''\n",
    "    # Metadata describing the text columns\n",
    "    \n",
    "    COLUMNS = ['pass_1', 'pass_2', 'path']\n",
    "    FIELD_DEFAULTS = [[\"\"], [\"\"], [\"\"]]\n",
    "    \n",
    "    # Decode the line into its fields\n",
    "    fields = tf.decode_csv(line, FIELD_DEFAULTS)\n",
    "\n",
    "    # Pack the result into a dictionary\n",
    "    features = dict(zip(COLUMNS,fields))\n",
    "\n",
    "    # Separate the label from the features\n",
    "    path = features.pop('path')\n",
    "\n",
    "    return features, path\n",
    "\n",
    "def csv_input_fn(csv_path, batch_size, skip_lines):\n",
    "    '''\n",
    "    This function builds a batch from the dataset in the CSV file.\n",
    "    '''\n",
    "    # Create a dataset containing the text lines.\n",
    "    dataset = tf.data.TextLineDataset(csv_path).skip(skip_lines)\n",
    "\n",
    "    # Parse each line.\n",
    "    dataset = dataset.map(_parse_line)\n",
    "\n",
    "    # Shuffle, repeat, and batch the examples.\n",
    "    dataset = dataset.shuffle(1000).repeat().batch(batch_size)\n",
    "\n",
    "    # Return the dataset.\n",
    "    return dataset\n",
    "\n",
    "def csv_input_fn_filter(csv_path, batch_size, skip_lines, edit_distance, limit=-1):\n",
    "    '''\n",
    "    This function builds a batch from the dataset in the CSV file, and filters out\n",
    "    samples that do not satisfy the edit distance condition.\n",
    "    '''\n",
    "    # Create a dataset containing the text lines.\n",
    "    dataset = tf.data.TextLineDataset(csv_path).skip(skip_lines).take(limit)\n",
    "\n",
    "    # Parse each line.\n",
    "    dataset = dataset.map(_parse_line)\n",
    "    \n",
    "    # Filter\n",
    "    dataset = dataset.filter(lambda feat, path : tf.less_equal(tf.size((tf.string_split(tf.reshape(path, shape=(1,)), \" []\"))), edit_distance))\n",
    "\n",
    "    # Shuffle, repeat, and batch the examples.\n",
    "    dataset = dataset.shuffle(1000).repeat().batch(batch_size)\n",
    "\n",
    "    # Return the dataset.\n",
    "    return dataset\n",
    "\n",
    "def pad_sequence_batch(sequence_batch, pad_int):\n",
    "    \"\"\"\n",
    "    Pad sequences with <PAD> = <EOS> so that each sequence of a batch has the same length\n",
    "    \"\"\"\n",
    "    max_sequence = max([len(seq) for seq in sequence_batch])\n",
    "    return [seq + [pad_int] * (max_sequence - len(seq)) for seq in sequence_batch]\n",
    "\n",
    "def preprocess_batch(batch, source_vocab_to_int, target_vocab_to_int):\n",
    "    #kb = Keyboard()\n",
    "    pass_batch = [kb.word_to_keyseq(d.decode('utf-8')) for d in batch[0]['pass_1']]\n",
    "    pass2_batch = [kb.word_to_keyseq(d.decode('utf-8')) for d in batch[0]['pass_2']]\n",
    "    path_batch = [json.loads(j) for j in [d.decode('utf-8') for d in batch[1]]]\n",
    "    pass_batch_ids, path_batch_ids = input_to_ids(pass_batch, path_batch,\n",
    "                                                      source_vocab_to_int, target_vocab_to_int)\n",
    "    source_pad_int = source_vocab_to_int['<EOS>']\n",
    "    target_pad_int = target_vocab_to_int['<EOS>']\n",
    "    # Pad\n",
    "    pad_sources_batch = np.array(pad_sequence_batch(pass_batch_ids, source_pad_int))\n",
    "    pad_targets_batch = np.array(pad_sequence_batch(path_batch_ids, target_pad_int))\n",
    "\n",
    "    # Need the lengths for the _lengths parameters\n",
    "    pad_targets_lengths = []\n",
    "    for target in pad_targets_batch:\n",
    "        pad_targets_lengths.append(len(target))\n",
    "\n",
    "    pad_source_lengths = []\n",
    "    for source in pad_sources_batch:\n",
    "        pad_source_lengths.append(len(source))\n",
    "    return (np.array(pad_sources_batch), np.array(pad_targets_batch), \n",
    "            np.array(pad_source_lengths), np.array(pad_targets_lengths), pass_batch, pass2_batch)\n",
    "\n",
    "def get_accuracy_beam(target, logits, pad_int=0):\n",
    "    \"\"\"\n",
    "    Calculate accuracy of BeamSearch output as follows: if one of the K outputs is correct,\n",
    "    it counts as a correct prediction (positive contribution to the accuracy).\n",
    "    \"logits\" are now of the shape: [batches, max_seq, K]\n",
    "    \"\"\"\n",
    "#     print(target.shape)\n",
    "#     print(logits.shape)\n",
    "    max_seq = max(target.shape[1], logits.shape[1])\n",
    "    if max_seq - target.shape[1]:\n",
    "        target = np.pad(target,\n",
    "            [(0,0),(0,max_seq - target.shape[1])],\n",
    "            'constant', constant_values = pad_int)\n",
    "    if max_seq - logits.shape[1]:\n",
    "        logits = np.pad(logits,\n",
    "            [(0,0), (0,max_seq - logits.shape[1]), (0,0)],\n",
    "            'constant', constant_values = pad_int)\n",
    "#     print(target)\n",
    "#     print(logits)\n",
    "    acc = [np.mean(np.equal(target, np.reshape(logits[:,:,i], target.shape))) for i in range(logits.shape[2])]\n",
    "#     if (max(acc) > 0.6):\n",
    "#         print(target)\n",
    "#         print(np.reshape(np.transpose(logits[:,:,acc.index(max(acc))]),\n",
    "#         target.shape))\n",
    "    return max(acc)\n",
    "\n",
    "def pass_to_seq(password, vocab_to_int):\n",
    "    '''\n",
    "    This function transforms password to sequence of integers, in order to make the tested password\n",
    "    applicable to the network's input.\n",
    "    '''\n",
    "    results = []\n",
    "    for c in list(password):\n",
    "        if c in vocab_to_int:\n",
    "            results.append(vocab_to_int[c])\n",
    "        else:\n",
    "            results.append(vocab_to_int['<UNK>'])\n",
    "            \n",
    "    return results\n",
    "\n",
    "def path2word_kb_feasible(word, path, print_path=False):\n",
    "    '''\n",
    "    This function decodes the word in which the given path transitions the input word into.\n",
    "    This is the KeyPress version, which handles the keyboard representations.\n",
    "    If one of the parts components is not feasible (e.g removing a char from out of range index), it skips it\n",
    "    Input parameters: original word, transition path\n",
    "    Output: decoded word\n",
    "    '''\n",
    "    #kb = Keyboard()\n",
    "    word = kb.word_to_keyseq(word)\n",
    "    if not path:\n",
    "        return kb.keyseq_to_word(word)\n",
    "    #path = [literal_eval(p) for p in path]\n",
    "    if (print_path):\n",
    "        print(path)\n",
    "#     print(type(path))\n",
    "#     print(word)\n",
    "    final_word = []\n",
    "    word_len = len(word)\n",
    "    path_len = len(path)\n",
    "    i = 0\n",
    "    j = 0\n",
    "    while (i < word_len or j < path_len):\n",
    "        if ((j < path_len and path[j][2] == i) or (i >= word_len and path[j][2] >= i)):\n",
    "            if (path[j][0] == \"s\"):\n",
    "                # substitute\n",
    "                final_word.append(path[j][1])\n",
    "                i += 1\n",
    "                j += 1\n",
    "            elif (path[j][0] == \"d\"):\n",
    "                # delete\n",
    "                i += 1\n",
    "                j += 1\n",
    "            else:\n",
    "                # \"i\", insert\n",
    "                final_word.append(path[j][1])\n",
    "                j += 1\n",
    "        else:\n",
    "            if (i < word_len):\n",
    "                final_word.append(word[i])\n",
    "                i += 1\n",
    "            if (j < path_len and i > path[j][2]):\n",
    "                j += 1\n",
    "    return (kb.keyseq_to_word(''.join(final_word)))\n",
    "\n",
    "def path_to_pass(password, idx_path, trans_dict):\n",
    "    '''\n",
    "    This function decodes the password in which the given path transitions the input password into.\n",
    "    Input parameters: original password, transition path, transition dictionary\n",
    "    Output: decoded password\n",
    "    '''\n",
    "#     print(idx_path)\n",
    "    str_path = []\n",
    "    for i in idx_path:\n",
    "        if (i != '<PAD>' and i != '<UNK>') and trans_dict.get(int(i)):\n",
    "            str_path.append(trans_dict[int(i)])\n",
    "#         else:\n",
    "#             print(\"could not find \" + str(i) + \" in dictionary\")\n",
    "#     print(str_path)\n",
    "    output_pass = path2word_kb_feasible(password, str_path)\n",
    "    return output_pass\n",
    "\n",
    "def get_accuracy_beam_decode(logits, pass1_batch, pass2_batch, target_int_to_vocab, trans_dict_2path, bias=False):\n",
    "    \"\"\"\n",
    "    Calculate accuracy of BeamSearch output as follows: if one of the K outputs is correct,\n",
    "    it counts as a correct prediction (positive contribution to the accuracy).\n",
    "    \"logits\" are now of the shape: [batches, max_seq, K]\n",
    "    \"\"\"\n",
    "#     print(logits.shape)\n",
    "    beam_width = logits.shape[2]\n",
    "    match_vec = np.zeros((1, logits.shape[0]), dtype=bool)\n",
    "    for i in range(beam_width):\n",
    "        decode_pred_batch = logits[:,:,i]\n",
    "        for k in range(logits.shape[0]):\n",
    "            decode_pred = logits[k,:,i]\n",
    "#             print(decode_pred)\n",
    "            path_idx_pred = [target_int_to_vocab[j] for j in decode_pred]\n",
    "#             print(path_idx_pred)\n",
    "            if ('<EOS>' in path_idx_pred):\n",
    "                path_idx_pred = path_idx_pred[:path_idx_pred.index('<EOS>')]\n",
    "            prediction = path_to_pass(pass1_batch[k], path_idx_pred, trans_dict_2path)\n",
    "#             print(\"pred: {}, targ: {}\".format(prediction, pass2_batch[k]))\n",
    "            if (prediction == kb.keyseq_to_word(pass2_batch[k])):\n",
    "#                 print(prediction)\n",
    "                match_vec[0, k] = True\n",
    "            if (bias and (not match_vec[0, k]) and (k == logits.shape[0] - 1)):\n",
    "                if (kb.keyseq_to_word(pass2_batch[k]) == kb.keyseq_to_word(pass1_batch[k])):\n",
    "                    match_vec[0, k] = True       \n",
    "    acc = np.mean(match_vec)\n",
    "#     if (max(acc) > 0.6):\n",
    "#         print(target)\n",
    "#         print(np.reshape(np.transpose(logits[:,:,acc.index(max(acc))]),\n",
    "#         target.shape))\n",
    "    return acc\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train():\n",
    "    trans_dict_2path = IDX_to_TRANS\n",
    "    #print(FLAGS.__flags.items())\n",
    "    f_path = FLAGS.ds_csv_path\n",
    "    batch_size = FLAGS.batch_size\n",
    "    edit_distance = FLAGS.edit_distance\n",
    "    # Initiate TF session\n",
    "    with tf.Session(config=tf.ConfigProto(allow_soft_placement=FLAGS.allow_soft_placement, \n",
    "        log_device_placement=FLAGS.log_device_placement, gpu_options=tf.GPUOptions(allow_growth=True))) as sess:\n",
    "        print('Loading training data..')\n",
    "        if (\"cleaned_pw_paths_tr.csv\" in f_path and edit_distance == 3):\n",
    "            num_samples = NUM_SAMPLES_LARGE_DS\n",
    "        elif (\"cleaned_pw_paths_tr.l8c3.csv\" in f_path and edit_distance == 3):\n",
    "            num_samples = NUM_SAMPLES_CORNELL_DS\n",
    "        else:\n",
    "            num_samples = 0\n",
    "            with open(f_path) as csv_file:\n",
    "                csv_reader = csv.reader(csv_file, delimiter=',')\n",
    "                num_samples = sum(1 for row in csv_reader if len(json.loads(row[2])) <= edit_distance)\n",
    "\n",
    "        total_batches = num_samples // batch_size\n",
    "\n",
    "        print(\"# Samples: {}\".format(num_samples))\n",
    "        print(\"Total batches: {}\".format(total_batches))\n",
    "\n",
    "        # Split data to training and validation sets\n",
    "        num_validation = int(0.2 * num_samples)\n",
    "        total_valid_batches = num_validation // batch_size\n",
    "        total_train_batches = total_batches - total_valid_batches\n",
    "\n",
    "        print(\"Total validation batches: {}\".format(total_valid_batches))\n",
    "        print(\"Total training batches: {}\".format(total_train_batches))\n",
    "\n",
    "        valid_dataset = csv_input_fn_filter(f_path, batch_size, skip_lines = 0,\n",
    "                                            edit_distance = edit_distance, limit = num_validation)\n",
    "        train_dataset = csv_input_fn_filter(f_path, batch_size, skip_lines = num_validation,\n",
    "                                            edit_distance = edit_distance, limit = -1)\n",
    "\n",
    "        valid_iterator = valid_dataset.make_initializable_iterator()\n",
    "        train_iterator = train_dataset.make_initializable_iterator()\n",
    "\n",
    "        next_valid_element = valid_iterator.get_next()\n",
    "        next_train_element = train_iterator.get_next()\n",
    "\n",
    "        sess.run(valid_iterator.initializer)\n",
    "        sess.run(train_iterator.initializer)\n",
    "\n",
    "        # Create a log writer object\n",
    "        log_writer = tf.summary.FileWriter(FLAGS.model_dir, graph=sess.graph)\n",
    "        \n",
    "        # Create a new model or reload existing checkpoint\n",
    "        model = create_model(sess, FLAGS)\n",
    "\n",
    "        step_time, loss = 0.0, 0.0\n",
    "        words_seen, sents_seen = 0, 0\n",
    "        start_time = time.time()\n",
    "        global_start_time = start_time\n",
    "\n",
    "        # Training loop\n",
    "        print('Training..')\n",
    "        for epoch_idx in range(FLAGS.max_epochs):\n",
    "            if (model.global_epoch_step.eval() >= FLAGS.max_epochs):\n",
    "                print('Training is already complete.', \\\n",
    "                      'current epoch:{}, max epoch:{}'.format(model.global_epoch_step.eval(), FLAGS.max_epochs))\n",
    "                break\n",
    "\n",
    "            for batch_i in range(total_train_batches):    \n",
    "                # Get a batch\n",
    "                batch_train = sess.run(next_train_element)\n",
    "                \n",
    "        \n",
    "                (source_batch, target_batch, sources_lengths, targets_lengths, pass1_train_batch,\n",
    "                 pass2_train_batch) = preprocess_batch(batch_train, \n",
    "                                                       source_vocab_to_int,\n",
    "                                                       target_vocab_to_int)\n",
    "\n",
    "                # Execute a single training step\n",
    "                step_loss, summary = model.train(sess, encoder_inputs=source_batch, encoder_inputs_length=sources_lengths, \n",
    "                                                 decoder_inputs=target_batch, decoder_inputs_length=targets_lengths)\n",
    "#                 print(step_loss)\n",
    "\n",
    "                loss += float(step_loss) / FLAGS.display_freq\n",
    "                words_seen += float(np.sum(sources_lengths + targets_lengths))\n",
    "                sents_seen += float(source_batch.shape[0]) # batch_size\n",
    "\n",
    "                if (model.global_step.eval() % FLAGS.display_freq == 0):\n",
    "                    # CHANGE TO ACCURACY\n",
    "                    avg_perplexity = math.exp(float(loss)) if loss < 300 else float(\"inf\")\n",
    "\n",
    "                    time_elapsed = time.time() - start_time\n",
    "                    step_time = time_elapsed / FLAGS.display_freq\n",
    "\n",
    "                    words_per_sec = words_seen / time_elapsed\n",
    "                    sents_per_sec = sents_seen / time_elapsed\n",
    "\n",
    "                    print('Epoch ', model.global_epoch_step.eval(), 'Batch: {}/{}'.format(batch_i, total_train_batches) , 'Step ', model.global_step.eval(), \\\n",
    "                          'Step-time {0:.2f}'.format(step_time), 'Total-time: {0:.2f}'.format(time.time() - global_start_time), \\\n",
    "                          '{0:.2f} passwords/s'.format(sents_per_sec), '{0:.2f} tokens/s'.format(words_per_sec), \\\n",
    "                            'Loss: {0:.3f}'.format(loss))\n",
    "\n",
    "                    loss = 0\n",
    "                    words_seen = 0\n",
    "                    sents_seen = 0\n",
    "                    start_time = time.time()\n",
    "                    \n",
    "                    # Record training summary for the current batch\n",
    "                    log_writer.add_summary(summary, model.global_step.eval())\n",
    "\n",
    "                # Execute a validation step\n",
    "                if (model.global_step.eval() % FLAGS.valid_freq == 0):\n",
    "                    print('Validation step')\n",
    "                    batch_valid = sess.run(next_valid_element)\n",
    "                    (valid_sources_batch, valid_targets_batch, valid_sources_lengths, valid_targets_lengths,\n",
    "                        pass1_valid_batch, pass2_valid_batch) = preprocess_batch(batch_valid, \n",
    "                                                                                 source_vocab_to_int,\n",
    "                                                                                 target_vocab_to_int)\n",
    "                    valid_loss = model.eval(sess, encoder_inputs=valid_sources_batch, encoder_inputs_length=valid_sources_lengths,\n",
    "                                               decoder_inputs=valid_targets_batch, decoder_inputs_length=valid_targets_lengths)\n",
    "                    print('Valid Loss: {0:.2f}'.format(valid_loss[0]))\n",
    "\n",
    "                # Save the model checkpoint\n",
    "                if (model.global_step.eval() % FLAGS.save_freq == 0):\n",
    "                    print('Saving the model..')\n",
    "                    checkpoint_path = os.path.join(FLAGS.model_dir, FLAGS.model_name)\n",
    "                    model.save(sess, checkpoint_path, global_step=model.global_step)\n",
    "                    json.dump(model.config,\n",
    "                              open('%s-%d.json' % (checkpoint_path, model.global_step.eval()), 'w'),\n",
    "                              indent=2)\n",
    "            # Increase the epoch index of the model\n",
    "            model.global_epoch_step_op.eval()\n",
    "            print('Epoch {0:} DONE'.format(model.global_epoch_step.eval()))\n",
    "        \n",
    "        print('Saving the last model..')\n",
    "        checkpoint_path = os.path.join(FLAGS.model_dir, FLAGS.model_name)\n",
    "        model.save(sess, checkpoint_path, global_step=model.global_step)\n",
    "        json.dump(model.config,\n",
    "                  open('%s-%d.json' % (checkpoint_path, model.global_step.eval()), 'w'),\n",
    "                  indent=2)\n",
    "        total_time = time.time() - global_start_time\n",
    "        \n",
    "    print('Training Terminated, Total time: {} seconds'.format(total_time))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loading training data..\n",
      "# Samples: 1156\n",
      "Total batches: 23\n",
      "Total validation batches: 4\n",
      "Total training batches: 19\n",
      "building model..\n",
      "building encoder..\n",
      "building decoder and attention..\n",
      "setting optimizer..\n",
      "Reloading model parameters..\n",
      "INFO:tensorflow:Restoring parameters from model/pass2path.ckpt-5600\n",
      "model restored from model/pass2path.ckpt-5600\n",
      "Training..\n",
      "Epoch  450 Step  5610 Perplexity 217.58 Step-time 0.19 257.36 sents/s 5481.70 tokens/s Loss: 5.383\n",
      "Epoch 451 DONE\n",
      "Epoch  451 Step  5620 Perplexity 12.45 Step-time 0.05 991.22 sents/s 17048.90 tokens/s Loss: 2.521\n",
      "Epoch  451 Step  5630 Perplexity 6.34 Step-time 0.08 662.76 sents/s 11730.94 tokens/s Loss: 1.847\n",
      "Epoch 452 DONE\n",
      "Epoch  452 Step  5640 Perplexity 5.40 Step-time 0.05 989.27 sents/s 18895.03 tokens/s Loss: 1.687\n",
      "Validation step\n",
      "Valid Loss: 3.076057195663452\n",
      "Epoch  452 Step  5650 Perplexity 4.31 Step-time 0.10 494.39 sents/s 9344.04 tokens/s Loss: 1.460\n",
      "Epoch 453 DONE\n",
      "Epoch  453 Step  5660 Perplexity 3.49 Step-time 0.05 994.15 sents/s 19087.59 tokens/s Loss: 1.250\n",
      "Epoch  453 Step  5670 Perplexity 3.27 Step-time 0.07 682.08 sents/s 11800.03 tokens/s Loss: 1.185\n",
      "Epoch 454 DONE\n",
      "Epoch  454 Step  5680 Perplexity 2.82 Step-time 0.05 946.54 sents/s 19688.03 tokens/s Loss: 1.037\n",
      "Validation step\n",
      "Valid Loss: 3.426955223083496\n",
      "Epoch  454 Step  5690 Perplexity 2.85 Step-time 0.08 625.74 sents/s 11889.04 tokens/s Loss: 1.048\n",
      "Epoch 455 DONE\n",
      "Epoch  455 Step  5700 Perplexity 2.53 Step-time 0.05 989.35 sents/s 19094.43 tokens/s Loss: 0.930\n",
      "Epoch  455 Step  5710 Perplexity 2.63 Step-time 0.08 663.20 sents/s 11606.01 tokens/s Loss: 0.968\n",
      "Epoch 456 DONE\n",
      "Epoch  456 Step  5720 Perplexity 2.48 Step-time 0.05 1001.06 sents/s 19720.84 tokens/s Loss: 0.910\n",
      "Validation step\n",
      "Valid Loss: 3.137817859649658\n",
      "Epoch  456 Step  5730 Perplexity 2.36 Step-time 0.08 633.21 sents/s 12157.55 tokens/s Loss: 0.858\n",
      "Epoch 457 DONE\n",
      "Epoch  457 Step  5740 Perplexity 2.24 Step-time 0.05 983.48 sents/s 18686.10 tokens/s Loss: 0.804\n",
      "Epoch  457 Step  5750 Perplexity 2.16 Step-time 0.07 670.26 sents/s 12734.87 tokens/s Loss: 0.771\n",
      "Epoch 458 DONE\n",
      "Epoch  458 Step  5760 Perplexity 2.06 Step-time 0.05 929.10 sents/s 19232.29 tokens/s Loss: 0.723\n",
      "Validation step\n",
      "Valid Loss: 3.459542989730835\n",
      "Epoch  458 Step  5770 Perplexity 2.15 Step-time 0.05 970.23 sents/s 17464.06 tokens/s Loss: 0.765\n",
      "Epoch 459 DONE\n",
      "Epoch  459 Step  5780 Perplexity 1.97 Step-time 0.08 661.46 sents/s 11575.55 tokens/s Loss: 0.677\n",
      "Epoch  459 Step  5790 Perplexity 2.03 Step-time 0.05 1027.59 sents/s 18085.58 tokens/s Loss: 0.707\n",
      "Epoch 460 DONE\n",
      "Epoch  460 Step  5800 Perplexity 1.98 Step-time 0.08 602.55 sents/s 13798.40 tokens/s Loss: 0.681\n",
      "Validation step\n",
      "Valid Loss: 3.9332146644592285\n",
      "Epoch 461 DONE\n",
      "Epoch  461 Step  5810 Perplexity 1.91 Step-time 0.05 973.97 sents/s 17434.15 tokens/s Loss: 0.648\n",
      "Epoch  461 Step  5820 Perplexity 1.86 Step-time 0.08 666.29 sents/s 11260.31 tokens/s Loss: 0.621\n",
      "Epoch 462 DONE\n",
      "Epoch  462 Step  5830 Perplexity 1.84 Step-time 0.05 983.55 sents/s 18687.45 tokens/s Loss: 0.610\n",
      "Epoch  462 Step  5840 Perplexity 1.94 Step-time 0.08 638.45 sents/s 13343.65 tokens/s Loss: 0.662\n",
      "Validation step\n",
      "Valid Loss: 3.617180109024048\n",
      "Epoch 463 DONE\n",
      "Epoch  463 Step  5850 Perplexity 1.83 Step-time 0.05 913.93 sents/s 17913.00 tokens/s Loss: 0.605\n",
      "Epoch  463 Step  5860 Perplexity 1.84 Step-time 0.07 681.59 sents/s 12200.39 tokens/s Loss: 0.609\n",
      "Epoch 464 DONE\n",
      "Epoch  464 Step  5870 Perplexity 1.75 Step-time 0.05 1034.97 sents/s 17698.07 tokens/s Loss: 0.560\n",
      "Epoch  464 Step  5880 Perplexity 1.80 Step-time 0.08 662.80 sents/s 13057.15 tokens/s Loss: 0.586\n",
      "Validation step\n",
      "Valid Loss: 3.411146640777588\n",
      "Epoch 465 DONE\n",
      "Epoch  465 Step  5890 Perplexity 1.74 Step-time 0.05 988.22 sents/s 17293.93 tokens/s Loss: 0.556\n",
      "Epoch  465 Step  5900 Perplexity 1.80 Step-time 0.08 627.30 sents/s 13424.15 tokens/s Loss: 0.586\n",
      "Epoch 466 DONE\n",
      "Epoch  466 Step  5910 Perplexity 1.74 Step-time 0.05 966.51 sents/s 18653.58 tokens/s Loss: 0.553\n",
      "Epoch  466 Step  5920 Perplexity 1.77 Step-time 0.05 997.10 sents/s 18944.91 tokens/s Loss: 0.570\n",
      "Validation step\n",
      "Valid Loss: 4.092990398406982\n",
      "Epoch 467 DONE\n",
      "Epoch  467 Step  5930 Perplexity 1.64 Step-time 0.08 627.69 sents/s 12302.67 tokens/s Loss: 0.493\n",
      "Epoch  467 Step  5940 Perplexity 1.72 Step-time 0.05 987.41 sents/s 19254.54 tokens/s Loss: 0.544\n",
      "Epoch 468 DONE\n",
      "Epoch  468 Step  5950 Perplexity 1.65 Step-time 0.08 657.15 sents/s 12551.58 tokens/s Loss: 0.499\n",
      "Epoch  468 Step  5960 Perplexity 1.73 Step-time 0.05 965.66 sents/s 18830.39 tokens/s Loss: 0.547\n",
      "Validation step\n",
      "Valid Loss: 4.003304481506348\n",
      "Epoch 469 DONE\n",
      "Epoch  469 Step  5970 Perplexity 1.65 Step-time 0.08 640.86 sents/s 12368.50 tokens/s Loss: 0.502\n",
      "Epoch  469 Step  5980 Perplexity 1.60 Step-time 0.05 1065.61 sents/s 17902.24 tokens/s Loss: 0.467\n",
      "Epoch 470 DONE\n",
      "Epoch  470 Step  5990 Perplexity 1.62 Step-time 0.08 653.76 sents/s 12682.95 tokens/s Loss: 0.484\n",
      "Epoch 471 DONE\n",
      "Epoch  471 Step  6000 Perplexity 1.63 Step-time 0.05 1046.87 sents/s 17901.41 tokens/s Loss: 0.487\n",
      "Validation step\n",
      "Valid Loss: 3.7523272037506104\n",
      "Epoch  471 Step  6010 Perplexity 1.68 Step-time 0.08 603.30 sents/s 12850.29 tokens/s Loss: 0.520\n",
      "Epoch 472 DONE\n",
      "Epoch  472 Step  6020 Perplexity 1.66 Step-time 0.05 951.89 sents/s 19894.48 tokens/s Loss: 0.508\n",
      "Epoch  472 Step  6030 Perplexity 1.63 Step-time 0.08 625.75 sents/s 12014.34 tokens/s Loss: 0.489\n",
      "Epoch 473 DONE\n",
      "Epoch  473 Step  6040 Perplexity 1.57 Step-time 0.05 1010.08 sents/s 19292.62 tokens/s Loss: 0.452\n",
      "Validation step\n",
      "Valid Loss: 3.7166531085968018\n",
      "Epoch  473 Step  6050 Perplexity 1.61 Step-time 0.08 660.20 sents/s 11751.52 tokens/s Loss: 0.478\n",
      "Epoch 474 DONE\n",
      "Epoch  474 Step  6060 Perplexity 1.58 Step-time 0.05 974.87 sents/s 18912.50 tokens/s Loss: 0.457\n",
      "Epoch  474 Step  6070 Perplexity 1.61 Step-time 0.05 990.33 sents/s 19014.30 tokens/s Loss: 0.474\n",
      "Epoch 475 DONE\n",
      "Epoch  475 Step  6080 Perplexity 1.53 Step-time 0.08 644.95 sents/s 11351.20 tokens/s Loss: 0.423\n",
      "Validation step\n",
      "Valid Loss: 4.4167656898498535\n",
      "Epoch  475 Step  6090 Perplexity 1.59 Step-time 0.06 908.13 sents/s 18889.06 tokens/s Loss: 0.466\n",
      "Epoch 476 DONE\n",
      "Epoch  476 Step  6100 Perplexity 1.55 Step-time 0.07 676.55 sents/s 11839.70 tokens/s Loss: 0.436\n",
      "Epoch  476 Step  6110 Perplexity 1.56 Step-time 0.05 961.97 sents/s 20201.34 tokens/s Loss: 0.447\n",
      "Epoch 477 DONE\n",
      "Epoch  477 Step  6120 Perplexity 1.58 Step-time 0.08 634.00 sents/s 13314.06 tokens/s Loss: 0.456\n",
      "Validation step\n",
      "Valid Loss: 3.9538259506225586\n",
      "Epoch  477 Step  6130 Perplexity 1.53 Step-time 0.05 990.24 sents/s 17032.16 tokens/s Loss: 0.428\n",
      "Epoch 478 DONE\n",
      "Epoch  478 Step  6140 Perplexity 1.54 Step-time 0.07 672.04 sents/s 11895.16 tokens/s Loss: 0.433\n",
      "Epoch  478 Step  6150 Perplexity 1.53 Step-time 0.05 933.41 sents/s 19601.66 tokens/s Loss: 0.428\n",
      "Epoch 479 DONE\n",
      "Epoch  479 Step  6160 Perplexity 1.51 Step-time 0.08 664.53 sents/s 11363.42 tokens/s Loss: 0.414\n",
      "Validation step\n",
      "Valid Loss: 3.98569917678833\n",
      "Epoch  479 Step  6170 Perplexity 1.51 Step-time 0.05 938.60 sents/s 17927.34 tokens/s Loss: 0.414\n",
      "Epoch 480 DONE\n",
      "Epoch  480 Step  6180 Perplexity 1.52 Step-time 0.08 655.44 sents/s 12584.45 tokens/s Loss: 0.416\n",
      "Epoch 481 DONE\n",
      "Epoch  481 Step  6190 Perplexity 1.45 Step-time 0.05 1030.74 sents/s 18141.03 tokens/s Loss: 0.375\n",
      "Epoch  481 Step  6200 Perplexity 1.58 Step-time 0.08 628.89 sents/s 13332.38 tokens/s Loss: 0.457\n",
      "Validation step\n",
      "Valid Loss: 4.081235408782959\n",
      "Epoch 482 DONE\n",
      "Epoch  482 Step  6210 Perplexity 1.50 Step-time 0.05 914.76 sents/s 18020.77 tokens/s Loss: 0.406\n",
      "Epoch  482 Step  6220 Perplexity 1.51 Step-time 0.05 997.13 sents/s 18945.42 tokens/s Loss: 0.412\n",
      "Epoch 483 DONE\n",
      "Epoch  483 Step  6230 Perplexity 1.47 Step-time 0.08 661.89 sents/s 11516.96 tokens/s Loss: 0.384\n",
      "Epoch  483 Step  6240 Perplexity 1.48 Step-time 0.05 976.81 sents/s 18657.07 tokens/s Loss: 0.392\n",
      "Validation step\n",
      "Valid Loss: 3.976433515548706\n",
      "Epoch 484 DONE\n",
      "Epoch  484 Step  6250 Perplexity 1.43 Step-time 0.08 593.29 sents/s 12874.36 tokens/s Loss: 0.360\n",
      "Epoch  484 Step  6260 Perplexity 1.48 Step-time 0.05 1000.06 sents/s 19001.19 tokens/s Loss: 0.391\n",
      "Epoch 485 DONE\n",
      "Epoch  485 Step  6270 Perplexity 1.48 Step-time 0.08 660.59 sents/s 12220.96 tokens/s Loss: 0.392\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch  485 Step  6280 Perplexity 1.48 Step-time 0.05 1041.39 sents/s 17911.96 tokens/s Loss: 0.393\n",
      "Validation step\n",
      "Valid Loss: 3.7619235515594482\n",
      "Epoch 486 DONE\n",
      "Epoch  486 Step  6290 Perplexity 1.46 Step-time 0.08 616.58 sents/s 11961.71 tokens/s Loss: 0.381\n",
      "Epoch  486 Step  6300 Perplexity 1.46 Step-time 0.05 950.15 sents/s 19953.23 tokens/s Loss: 0.380\n",
      "Epoch 487 DONE\n",
      "Epoch  487 Step  6310 Perplexity 1.45 Step-time 0.07 680.67 sents/s 11775.52 tokens/s Loss: 0.371\n",
      "Epoch  487 Step  6320 Perplexity 1.44 Step-time 0.05 990.32 sents/s 18717.06 tokens/s Loss: 0.365\n",
      "Validation step\n",
      "Valid Loss: 3.500795602798462\n",
      "Epoch 488 DONE\n",
      "Epoch  488 Step  6330 Perplexity 1.47 Step-time 0.08 633.57 sents/s 12418.02 tokens/s Loss: 0.385\n",
      "Epoch  488 Step  6340 Perplexity 1.44 Step-time 0.05 938.64 sents/s 19711.50 tokens/s Loss: 0.366\n",
      "Epoch 489 DONE\n",
      "Epoch  489 Step  6350 Perplexity 1.46 Step-time 0.07 682.55 sents/s 11398.57 tokens/s Loss: 0.381\n",
      "Epoch  489 Step  6360 Perplexity 1.41 Step-time 0.05 1028.64 sents/s 18309.78 tokens/s Loss: 0.345\n",
      "Validation step\n",
      "Valid Loss: 4.194618225097656\n",
      "Epoch 490 DONE\n",
      "Epoch  490 Step  6370 Perplexity 1.50 Step-time 0.06 884.33 sents/s 18747.85 tokens/s Loss: 0.408\n",
      "Epoch 491 DONE\n",
      "Epoch  491 Step  6380 Perplexity 1.45 Step-time 0.08 638.38 sents/s 12193.14 tokens/s Loss: 0.369\n",
      "Epoch  491 Step  6390 Perplexity 1.43 Step-time 0.05 1002.14 sents/s 19341.30 tokens/s Loss: 0.358\n",
      "Epoch 492 DONE\n",
      "Epoch  492 Step  6400 Perplexity 1.39 Step-time 0.08 652.93 sents/s 12340.39 tokens/s Loss: 0.331\n",
      "Validation step\n",
      "Valid Loss: 3.466080904006958\n",
      "Epoch  492 Step  6410 Perplexity 1.43 Step-time 0.05 952.87 sents/s 18390.44 tokens/s Loss: 0.355\n",
      "Epoch 493 DONE\n",
      "Epoch  493 Step  6420 Perplexity 1.41 Step-time 0.08 648.31 sents/s 12382.71 tokens/s Loss: 0.345\n",
      "Epoch  493 Step  6430 Perplexity 1.40 Step-time 0.05 973.04 sents/s 18974.19 tokens/s Loss: 0.336\n",
      "Epoch 494 DONE\n",
      "Epoch  494 Step  6440 Perplexity 1.40 Step-time 0.08 650.82 sents/s 12625.87 tokens/s Loss: 0.335\n",
      "Validation step\n",
      "Valid Loss: 4.736934661865234\n",
      "Epoch  494 Step  6450 Perplexity 1.37 Step-time 0.05 947.37 sents/s 17999.95 tokens/s Loss: 0.313\n",
      "Epoch 495 DONE\n",
      "Epoch  495 Step  6460 Perplexity 1.41 Step-time 0.08 657.11 sents/s 11368.04 tokens/s Loss: 0.340\n",
      "Epoch  495 Step  6470 Perplexity 1.37 Step-time 0.05 994.22 sents/s 19486.75 tokens/s Loss: 0.314\n",
      "Epoch 496 DONE\n",
      "Epoch  496 Step  6480 Perplexity 1.40 Step-time 0.08 655.87 sents/s 11412.06 tokens/s Loss: 0.337\n",
      "Validation step\n",
      "Valid Loss: 3.988368034362793\n",
      "Epoch  496 Step  6490 Perplexity 1.39 Step-time 0.05 974.05 sents/s 17435.51 tokens/s Loss: 0.326\n",
      "Epoch 497 DONE\n",
      "Epoch  497 Step  6500 Perplexity 1.41 Step-time 0.08 597.90 sents/s 12436.41 tokens/s Loss: 0.347\n",
      "Epoch  497 Step  6510 Perplexity 1.37 Step-time 0.05 939.48 sents/s 19541.20 tokens/s Loss: 0.317\n",
      "Epoch 498 DONE\n",
      "Epoch  498 Step  6520 Perplexity 1.40 Step-time 0.06 869.77 sents/s 15394.94 tokens/s Loss: 0.336\n",
      "Validation step\n",
      "Valid Loss: 3.8093183040618896\n",
      "Epoch  498 Step  6530 Perplexity 1.36 Step-time 0.08 632.38 sents/s 11066.65 tokens/s Loss: 0.311\n",
      "Epoch 499 DONE\n",
      "Epoch  499 Step  6540 Perplexity 1.41 Step-time 0.05 963.65 sents/s 18887.61 tokens/s Loss: 0.345\n",
      "Epoch  499 Step  6550 Perplexity 1.35 Step-time 0.08 628.50 sents/s 12067.17 tokens/s Loss: 0.300\n",
      "Epoch 500 DONE\n",
      "Training is already complete. current epoch:500, max epoch:500\n",
      "Saving the last model..\n",
      "model saved at model/pass2path.ckpt-6550\n",
      "Training Terminated\n"
     ]
    },
    {
     "ename": "SystemExit",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "An exception has occurred, use %tb to see the full traceback.\n",
      "\u001b[1;31mSystemExit\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\ProgramData\\Anaconda3\\envs\\tensorflow\\lib\\site-packages\\IPython\\core\\interactiveshell.py:2971: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n",
      "  warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n"
     ]
    }
   ],
   "source": [
    "def main(_):\n",
    "    train()\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    tf.reset_default_graph()\n",
    "    tf.app.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_items([('num_encoder_symbols', <absl.flags._flag.Flag object at 0x0000026459CD4C50>), ('hidden_units', <absl.flags._flag.Flag object at 0x0000026459CD4E48>), ('log_device_placement', <absl.flags._flag.BooleanFlag object at 0x0000026459AA5198>), ('batch_size', <absl.flags._flag.Flag object at 0x0000026459CD46A0>), ('num_decoder_symbols', <absl.flags._flag.Flag object at 0x0000026459CD4BA8>), ('use_fp16', <absl.flags._flag.BooleanFlag object at 0x0000026459CD40F0>), ('edit_distance', <absl.flags._flag.Flag object at 0x0000026459CD4898>), ('save_freq', <absl.flags._flag.Flag object at 0x0000026459CD4400>), ('model_dir', <absl.flags._flag.Flag object at 0x0000026459CD4208>), ('dropout_rate', <absl.flags._flag.Flag object at 0x0000026459CD4940>), ('display_freq', <absl.flags._flag.Flag object at 0x0000026459CD44A8>), ('use_residual', <absl.flags._flag.BooleanFlag object at 0x0000026459CD4AC8>), ('allow_soft_placement', <absl.flags._flag.BooleanFlag object at 0x0000026459CD4080>), ('use_dropout', <absl.flags._flag.BooleanFlag object at 0x0000026459CD4A20>), ('depth', <absl.flags._flag.Flag object at 0x0000026459CD4DA0>), ('cell_type', <absl.flags._flag.Flag object at 0x0000026459CD4F28>), ('max_gradient_norm', <absl.flags._flag.Flag object at 0x0000026459CD4748>), ('learning_rate', <absl.flags._flag.Flag object at 0x0000026459CD47F0>), ('summary_dir', <absl.flags._flag.Flag object at 0x0000026459CD4198>), ('model_name', <absl.flags._flag.Flag object at 0x0000026459CD4128>), ('ds_csv_path', <absl.flags._flag.Flag object at 0x0000026459CD4B00>), ('optimizer', <absl.flags._flag.Flag object at 0x0000026459CD42B0>), ('embedding_size', <absl.flags._flag.Flag object at 0x0000026459CD4CF8>), ('max_seq_length', <absl.flags._flag.Flag object at 0x0000026459CD4550>), ('valid_freq', <absl.flags._flag.Flag object at 0x0000026459CD4358>), ('max_epochs', <absl.flags._flag.Flag object at 0x0000026459CD45F8>)])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "FLAGS.__flags.items()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
